package com.ncmmall.api.apis.mall;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.ncmmall.api.apis.service.Result;
import com.ncmmall.api.params.DistributionApplyDTO;
import com.ncmmall.api.params.DistributionDTO;
import com.ncmmall.api.params.DistributionGoodsDTO;
import com.ncmmall.api.params.DistributionSelectGoodsDTO;
import com.ncmmall.api.security.Securitys;
import com.ncmmall.application.business.distribution.DistributionPosterApplication;
import com.ncmmall.application.business.distribution.DistributionSettingApplication;
import com.ncmmall.application.business.distribution.DistributorApplication;
import com.ncmmall.application.business.distribution.DistributorWithdrawRecordApplication;
import com.ncmmall.cache.redis.RedisService;
import com.feijin.commons.lang.ArithUtils;
import com.feijin.commons.lang.Requires;
import com.ncmmall.domain.business.bankcard.BankCard;
import com.ncmmall.domain.business.distribution.DistributionCheck;
import com.ncmmall.domain.business.distribution.DistributionGoods;
import com.ncmmall.domain.business.distribution.DistributionGoodsAssign;
import com.ncmmall.domain.business.distribution.DistributionOrder;
import com.ncmmall.domain.business.distribution.DistributionPoster;
import com.ncmmall.domain.business.distribution.DistributionSetting;
import com.ncmmall.domain.business.distribution.Distributor;
import com.ncmmall.domain.business.distribution.DistributorLevel;
import com.ncmmall.domain.business.distribution.DistributorWithdrawPayRecord;
import com.ncmmall.domain.business.distribution.DistributorWithdrawRecord;
import com.ncmmall.domain.business.distribution.QDistributionOrder;
import com.ncmmall.domain.business.distribution.QDistributor;
import com.ncmmall.domain.business.distribution.QDistributorLevel;
import com.ncmmall.domain.business.goods.Goods;
import com.ncmmall.domain.business.goods.channel.GoodsChannel;
import com.ncmmall.domain.business.goods.channel.QGoodsChannel;
import com.ncmmall.domain.business.order.Order;
import com.ncmmall.domain.security.user.QWebUser;
import com.ncmmall.domain.security.user.WebUser;
import com.ncmmall.querychannel.QueryPage;
import com.ncmmall.querychannel.QueryPageRequest;
import com.ncmmall.querychannel.service.QueryChannelService;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 分销API
 *
 * @author likaikai
 * @date 2020-08-24 19:29
 */
@RestController
@RequestMapping(value = "/distribution")
@Slf4j
public class DistributionApi {

    @Autowired
    private QueryChannelService queryChannelService;

    @Autowired
    private DistributorApplication distributorApplication;

    @Autowired
    private RedisService redisService;

    @Value("${store.domain}")
    private String storeDomain;

    @Autowired
    private DistributionPosterApplication distributionPosterApplication;

    @Autowired
    private DistributorWithdrawRecordApplication distributorWithdrawRecordApplication;

    @Autowired
    private DistributionSettingApplication distributionSettingApplication;

    /**
     * 分销商首页
     */
    @GetMapping("/home")
    public Result home(HttpServletRequest request) {
        Result result = new Result();
        try {

            WebUser user = Securitys.user(request);
            Distributor distributor = user.getDistributor();

            Requires.notNull(distributor, "当前用户不是分销商");
            Requires.isTrue(distributor.getAccountStatus() == 1, "分销商账号被禁用");
            Requires.isTrue(distributor.getMicroShop(), "微店被禁用");

            Map<String, Object> map = new HashMap<>();
            map.put("balance", user.getDistributor().getBalance());

            //待收入金额
            List<DistributionOrder> orders = queryChannelService.findAll(QDistributionOrder.distributionOrder.distributor.id.eq(distributor.getId()).and(QDistributionOrder.distributionOrder.distrtionPay.eq(1)), DistributionOrder.class);
            if (CollectionUtils.isNotEmpty(orders)) {
                map.put("noIncome", ArithUtils.roundHalfUp(orders.stream().mapToDouble(DistributionOrder::getMoney).sum(), 2));
            } else {
                map.put("noIncome", 0);
            }

            //本月收入金额
            orders = queryChannelService.queryAllEntity("select * from distribution_order where distributor_id = :did and distrtionPay = 2 and year(sendTime) = year(now()) and month(sendTime) = month(now())", ImmutableMap.of("did", distributor.getId()), DistributionOrder.class);
            if (CollectionUtils.isNotEmpty(orders)) {
                map.put("incomeMonth", ArithUtils.roundHalfUp(orders.stream().mapToDouble(DistributionOrder::getMoney).sum(), 2));
            } else {
                map.put("incomeMonth", 0);
            }

            //累计收入金额
            orders = queryChannelService.queryAllEntity("select * from distribution_order where distributor_id = :did and distrtionPay = 2", ImmutableMap.of("did", distributor.getId()), DistributionOrder.class);
            if (CollectionUtils.isNotEmpty(orders)) {
                map.put("incomeAll", ArithUtils.roundHalfUp(orders.stream().mapToDouble(DistributionOrder::getMoney).sum(), 2));
            } else {
                map.put("incomeAll", 0);
            }

            //已提现金额
            List<DistributorWithdrawPayRecord> records = queryChannelService.queryAllEntity("select * from distributor_withdraw_pay_record where distributor_id = :did and status = 2", ImmutableMap.of("did", distributor.getId()), DistributorWithdrawPayRecord.class);
            if (CollectionUtils.isNotEmpty(records)) {
                map.put("withdrawal", ArithUtils.roundHalfUp(records.stream().mapToDouble(DistributorWithdrawPayRecord::getPayMoney).sum(), 2));
            } else {
                map.put("withdrawal", 0);
            }

            //下级分销商数
            int count = queryChannelService.selectCount("select count(*) from security_web_user where father_id = :fid and distributor_id is not null", ImmutableMap.of("fid", user.getId()));

            //下级会员数
            int count2 = queryChannelService.selectCount("select count(*) from security_web_user where father_id = :fid and distributor_id is null", ImmutableMap.of("fid", user.getId()));

            //子孙分销商数
            List<WebUser> users = queryChannelService.queryAllEntity("select * from security_web_user where father_id = :fid and distributor_id is not null", ImmutableMap.of("fid", user.getId()), WebUser.class);
            List<Long> ids = users.stream().map(WebUser::getId).collect(Collectors.toList());
            ids.add(user.getId());

            int count3 = queryChannelService.selectCount("select count(*) from security_web_user where father_id in (:fids) and distributor_id is not null", ImmutableMap.of("fids", ids));

            //子孙会员数
            int count4 = queryChannelService.selectCount("select count(*) from security_web_user where father_id in (:fids) and distributor_id is null", ImmutableMap.of("fids", ids));

            //可返佣会员数
            int count5 = queryChannelService.selectCount("select count(*) from security_web_user where father_id in (:fids)", ImmutableMap.of("fids", ids));

            map.put("count", count);
            map.put("count2", count2);
            map.put("count3", count3);
            map.put("count4", count4);
            map.put("count5", count5);

            DistributionSetting setting = distributionSettingApplication.findLastSetting();
            if (setting == null) {
                map.put("commissionPayType", 1);
            } else {
                map.put("commissionPayType", setting.getCommissionPayType());
            }

            List<Order> orderList = queryChannelService.findAll("select o from Order o where o.distributionOrder = 1 and o.distributor.id = :did and o.status in (2, 3, 4, 5)",
                    ImmutableMap.of("did", distributor.getId()), Order.class);

            //累计销售额
            double totalSalePrice = 0;
            if (CollUtil.isNotEmpty(orderList)) {
                totalSalePrice = orderList.stream()
                        .filter(order -> order.getStatus() == 4 || order.getStatus() == 5)
                        .mapToDouble(Order::getPrice)
                        .sum();
            }
            map.put("totalSalePrice", NumberUtil.roundDown(totalSalePrice, 2));

            //本月销售额
            Date date = DateUtil.beginOfMonth(new Date()).toJdkDate();
            double currentMonthSalePrice = 0;
            if (CollUtil.isNotEmpty(orderList)) {
                currentMonthSalePrice = orderList.stream()
                        .filter(order -> order.getCreateTime().after(date) && (order.getStatus() == 4 || order.getStatus() == 5))
                        .mapToDouble(Order::getPrice)
                        .sum();
            }
            map.put("currentMonthSalePrice", NumberUtil.roundDown(currentMonthSalePrice, 2));

            //本月待收入销售额
            double currentMonthForIncomePrice = 0;
            if (CollUtil.isNotEmpty(orderList)) {
                currentMonthForIncomePrice = orderList.stream()
                        .filter(order -> order.getCreateTime().after(date) && (order.getStatus() == 2 || order.getStatus() == 3))
                        .mapToDouble(Order::getPrice)
                        .sum();
            }
            map.put("currentMonthForIncomePrice", NumberUtil.roundDown(currentMonthForIncomePrice, 2));
            return result.ok().inject(map);

        } catch (IllegalArgumentException e) {
            return result.fail().setMsg(e.getMessage());
        } catch (Exception e) {
            log.error("[获取分销商首页异常]", e);
            return result.fail().setMsg("获取数据异常");
        }
    }


    /**
     * 分销商等级
     */
    @GetMapping("/levelList")
    public Result levelList() {
        Result result = new Result();
        try {
            List<Map<String, Object>> data = queryChannelService.selectAllMap("select name, image, id, level from distributor_level", new HashMap<>());
            for (Map<String, Object> map : data) {
                map.put("image", storeDomain + "/uploads/" + MapUtils.getString(map, "image"));
            }
            return result.ok().inject(data);
        } catch (Exception e) {
            log.error("[获取分销商等级异常]", e);
            return result.fail().setMsg("获取数据异常");
        }
    }

    /**
     * 申请成为分销商 下一步 校验
     */
    @GetMapping("/checkNextApply")
    public Result checkNextApply(HttpServletRequest request, @RequestParam String levelName) {
        Result result = new Result();
        try {

            Requires.hasLength(levelName, "请选择申请的等级");

            DistributorLevel distributorLevel = queryChannelService.findOne(QDistributorLevel.distributorLevel.name.eq(levelName), DistributorLevel.class);
            Requires.notNull(distributorLevel, "分销商等级不存在");

            WebUser member = Securitys.user(request);
            if (member.getDistributor() != null && member.getDistributor().getLevel().getLevel() >= distributorLevel.getLevel()) {
                return result.fail().setMsg("只能申请更高等级的分销商");
            }

            Map<String, Object> data = new HashMap<>();
            data.put("status", distributorLevel.getApplyType());
            if (distributorLevel.getApplyType() == 1) {
                data.put("mobile", member.getMobile());
            }
            return result.ok().inject(data);

        } catch (IllegalArgumentException e) {
            return result.fail().setMsg(e.getMessage());
        } catch (Exception e) {
            log.error("[申请分销商校验异常]", e);
            return result.fail().setMsg("网络连接异常");
        }
    }

    /**
     * 免费申请提交
     * 当申请的等级为 applyType = 1 免费加入的时候的申请
     */
    @PostMapping("/apply")
    public Result apply(HttpServletRequest request, @RequestBody DistributionApplyDTO params) {
        Result result = new Result();
        try {
            Requires.hasLength(params.getLevelName(), "申请分销商等级不能为空");
            Requires.hasLength(params.getMobileCode(), "手机验证码不能为空");

            DistributorLevel level = queryChannelService.findOne(QDistributorLevel.distributorLevel.name.eq(params.getLevelName()), DistributorLevel.class);
            Requires.notNull(level, "申请等级不存在");

            WebUser member = Securitys.user(request);
            String mobileCode = redisService.get("msm-" + member.getMobile());

            Requires.isTrue(params.getMobileCode().equals(mobileCode), "验证码不正确");
            boolean checkStatus = distributorApplication.apply(member, level, params.getDistributorId());

            Map<String, Object> map = new HashMap<>();
            map.put("checkStatus", checkStatus);
            map.put("firstLevelScale", level.getFirstLevelScale());
            map.put("secondLevelScale", level.getSecondLevelScale());

            return result.ok().inject(map);

        } catch (IllegalArgumentException e) {
            return result.fail().setMsg(e.getMessage());
        } catch (Exception e) {
            log.error("[申请分销商异常]", e);
            return result.fail().setMsg("获取数据异常");
        }
    }

    /**
     * 审核详情
     */
    @GetMapping("/checkDetail")
    public Result checkDetail(HttpServletRequest request) {
        Result result = new Result();
        try {
            WebUser member = Securitys.user(request);
            Map<String, Object> data = new HashMap<>();
            DistributionCheck distributionCheck = queryChannelService.queryOneEntity("select * from distribution_check where member_id = :mid order by createTime desc limit 1", ImmutableMap.of("mid", member.getId()), DistributionCheck.class);
            if (distributionCheck == null) {
                data.put("checkStatus", 0);
                data.put("active", true);
            } else {
                data.put("checkStatus", distributionCheck.getCheckStatus());
                data.put("active", distributionCheck.isActivationFlag());
                data.put("firstLevelScale", distributionCheck.getDistributorLevel().getFirstLevelScale());
                data.put("secondLevelScale", distributionCheck.getDistributorLevel().getSecondLevelScale());
            }

            return result.ok().inject(data);

        } catch (Exception e) {
            log.error("[获取分销商审核详情异常]", e);
            return result.fail().setMsg("获取数据异常");
        }
    }

    /**
     * 申请分销商指定商品列表
     */
    @GetMapping("/assignGoodsList")
    public Result assignGoodsList(@RequestParam(defaultValue = "10") int pageSize, @RequestParam(defaultValue = "1") int pageNo, String levelName) {
        Result result = new Result();
        try {

            Requires.hasLength(levelName, "请输入等级");

            DistributorLevel distributorLevel = queryChannelService.findOne(QDistributorLevel.distributorLevel.name.eq(levelName), DistributorLevel.class);
            Requires.notNull(distributorLevel, "该等级不存在");

            QueryPageRequest pageRequest = new QueryPageRequest().setPageNo(pageNo).setPageSize(pageSize);

            List<Map<String, Object>> data = Lists.newArrayList();
            QueryPage<Goods> goods = queryChannelService.findPage("select d.goods from DistributorLevelApplyGoods d where d.distributorLevel.id = :lid", pageRequest.setParams(ImmutableMap.of("lid", distributorLevel.getId())), Goods.class);
            for (Goods good : goods.getResult()) {
                Map<String, Object> map = new HashMap<>();
                map.put("goodsId", good.getId());
                map.put("goodsName", good.getName());
                map.put("goodsImage", storeDomain + "/uploads/" + good.getDefaultImage());
                map.put("price", good.getDefaultPrice());
                data.add(map);
            }

            return result.ok().inject(new QueryPage<>(goods.getTotalCount(), data, pageNo, pageSize));
        } catch (IllegalArgumentException e) {
            return result.fail().setMsg(e.getMessage());
        } catch (Exception e) {
            log.error("[获取申请分销商指定商品列表异常]", e);
            return result.fail().setMsg("获取数据异常");
        }
    }

    /**
     * 激活分销商
     */
    @GetMapping("/activation")
    public Result activation(HttpServletRequest request, @RequestParam String mobileCode) {
        Result result = new Result();
        try {

            Requires.hasLength(mobileCode, "手机验证码不能为空");

            WebUser member = Securitys.user(request);

            String code = redisService.get("msm-" + member.getMobile());
            Requires.isTrue(mobileCode.equals(code), "手机验证码不正确");

            DistributionCheck distributionCheck = queryChannelService.queryOneEntity("select d.* from distribution_check d where d.member_id = :mid order by createTime desc limit 1", ImmutableMap.of("mid", member.getId()), DistributionCheck.class);
            Requires.isTrue(distributionCheck != null, "该用户未申请过分销商");
            Requires.isTrue(distributionCheck.getCheckStatus() == 2, "未审核通过，无法激活");

            distributorApplication.activation(distributionCheck);
            return result.ok();

        } catch (IllegalArgumentException e) {
            return result.fail().setMsg(e.getMessage());
        } catch (Exception e) {
            log.error("[激活分销商异常]", e);
            return result.fail().setMsg("获取数据异常");
        }
    }

    /**
     * 分销商信息
     */
    @GetMapping("/info")
    public Result info(HttpServletRequest request, Long distributorId) {
        Result result = new Result();
        try {

            WebUser user;
            Distributor distributor;
            if (distributorId == null) {
                user = Securitys.user(request);
                distributor = user.getDistributor();
                Requires.notNull(distributor, "当前用户不是分销商");
            } else {
                user = queryChannelService.findOne(QWebUser.webUser.distributor.id.eq(distributorId), WebUser.class);
                distributor = user.getDistributor();
                Requires.notNull(distributor, "分销商不存在");
            }

            Map<String, Object> map = new HashMap<>();
            map.put("id", distributor.getId());
            map.put("avatar", StringUtils.isBlank(user.getAvatar()) ? null : storeDomain + "/avatar/" + user.getAvatar());
            map.put("nickname", user.getNickname());
            map.put("shopName", distributor.getShopName());
            map.put("level", distributor.getLevel().getName() + "分销商");

            String image = distributor.getLevel().getImage();
            map.put("levelIcon", StringUtils.isBlank(image) ? null : storeDomain + "/uploads/" + image);
            map.put("mobile", user.getMobile());
            map.put("background", StringUtils.isBlank(distributor.getShopBackgroundImage()) ? null : storeDomain + "/uploads/" + distributor.getShopBackgroundImage());
            map.put("channelIds", distributor.getChannelIds());

            if (distributor.getLevel().getFirstLevelScale() != null) {
                map.put("firstLevelScale", ArithUtils.roundHalfUp(ArithUtils.mul(distributor.getLevel().getFirstLevelScale(), 100), 2) + "%");
            } else {
                map.put("firstLevelScale", "0%");
            }
            if (distributor.getLevel().getSecondLevelScale() != null) {
                map.put("secondLevelScale", ArithUtils.roundHalfUp(ArithUtils.mul(distributor.getLevel().getSecondLevelScale(), 100), 2) + "%");
            } else {
                map.put("secondLevelScale", "0%");
            }
            map.put("qq", user.getQq());
            map.put("shopCreateTime", DateFormatUtils.format(distributor.getCreateTime(), "yyyy年MM日dd日"));
            map.put("balance", distributor.getBalance());

            return result.ok().inject(map);
        } catch (IllegalArgumentException e) {
            return result.fail().setMsg(e.getMessage());
        } catch (Exception e) {
            log.error("[获取分销商信息异常]", e);
            return result.fail().setMsg("获取数据异常");
        }
    }

    /**
     * 修改分销商信息
     */
    @PutMapping("/modify")
    public Result modify(HttpServletRequest request, @RequestBody DistributionDTO dto) {
        Result result = new Result();
        try {
            Requires.isTrue(dto.getType() > 0, "请选择类型");
            Requires.hasLength(dto.getValue(), "内容不能为空");

            WebUser user = Securitys.user(request);
            Distributor distributor = user.getDistributor();
            Requires.notNull(distributor, "当前用户不是分销商");

            if (dto.getType() == 1) {
                distributorApplication.modifyBackground(distributor, dto.getValue());
            } else if (dto.getType() == 2) {
                Requires.isTrue(queryChannelService.selectCount("select count(*) from distributor where shopName = :shopName", ImmutableMap.of("shopName", dto.getValue())) == 0, "店铺名称已存在");
                distributorApplication.modifyShopName(distributor, dto.getValue());
            } else if (dto.getType() == 3) {
                distributorApplication.modifyNickname(user, dto.getValue());
            } else if (dto.getType() == 4) {
                Requires.isTrue(queryChannelService.selectCount("select count(*) from security_web_user where qq = :qq", ImmutableMap.of("qq", dto.getValue())) == 0, "qq号已存在");
                distributorApplication.modifyQQ(user, dto.getValue());
            } else {
                return result.fail().setMsg("类型错误");
            }
            return result.ok();
        } catch (IllegalArgumentException e) {
            return result.fail().setMsg(e.getMessage());
        } catch (Exception e) {
            log.error("[编辑分销商信息异常]", e);
            return result.fail().setMsg("获取数据异常");
        }
    }


    /**
     * 分销商商品列表
     *
     * @param type 1、默认（当前销售的商品列表）  2、全部商品  3、分类商品列表(用户访问)  4、新品商品列表(近一周添加到商品池内的商品)
     */
    @GetMapping("/goodsList")
    public Result goodsList(HttpServletRequest request, @RequestParam(defaultValue = "1") int pageNo,
                            @RequestParam(defaultValue = "10") int pageSize,
                            @RequestParam(defaultValue = "1") int type, Long distributorId, Long channelId) {

        Result result = new Result();
        try {
            Distributor distributor;
            if (distributorId != null) {
                distributor = queryChannelService.findOne(QDistributor.distributor.id.eq(distributorId), Distributor.class);
            } else {
                WebUser user = Securitys.user(request);
                distributor = user.getDistributor();
                distributorId = distributor.getId();
            }
            Requires.notNull(distributor, "分销商不存在");
            Requires.isTrue(distributor.getAccountStatus() == 1, "分销商账号被禁用");
            Requires.isTrue(distributor.getMicroShop(), "微店被禁用");

            QueryPageRequest pageRequest = new QueryPageRequest().setPageNo(pageNo).setPageSize(pageSize);
            Map<String, Object> map = new HashMap<>();
            map.put("did", distributorId);

            String hql = "select g from DistributionGoodsAssign g where g.distributor.id = :did";
            if (type == 1) {
                hql += " and g.status = 1";
            } else if (type == 3) {
                hql += " and g.thirdChannel = :cid";
                map.put("cid", channelId);
            } else if (type == 4) {
                Timestamp time = new Timestamp(System.currentTimeMillis() - 7 * 24 * 3600 * 1000);
                hql += " and g.distributionGoods.createTime > :time";
                map.put("time", time);
            }
            QueryPage<DistributionGoodsAssign> page = queryChannelService.findPage(hql, pageRequest.setParams(map), DistributionGoodsAssign.class);

            List<DistributionGoodsDTO> list = new ArrayList<>();
            for (DistributionGoodsAssign assign : page.getResult()) {
                Goods goods = assign.getDistributionGoods().getGoods();
                DistributionGoodsDTO dto = new DistributionGoodsDTO();
                dto.setGoodsId(goods.getId());
                dto.setAssignId(assign.getId());
                dto.setDefaultPrice(goods.getDefaultPrice());
                dto.setDefaultImage(StringUtils.isBlank(goods.getDefaultImage()) ? null : storeDomain + "/uploads/" + goods.getDefaultImage());
                dto.setDistributorId(distributorId);
                dto.setGoodsName(goods.getName());
                dto.setScale(ArithUtils.roundHalfUp((1 - assign.getDistributionGoods().getGuaranteeScale()) * 100, 2) + "%");
                list.add(dto);
            }

            return result.ok().inject(new QueryPage<>(page.getTotalCount(), list, pageNo, pageSize));

        } catch (IllegalArgumentException e) {
            return result.fail().setMsg(e.getMessage());
        } catch (Exception e) {
            log.error("[获取分销商品异常]", e);
            return result.fail().setMsg("获取数据异常");
        }
    }


    /**
     * 分销商商品分类列表
     *
     * @param type 1、默认（当前销售的商品分类）  2、全部商品分类
     */
    @GetMapping("/channels")
    public Result channels(HttpServletRequest request, @RequestParam(defaultValue = "1") int type, Long distributorId) {
        Result result = new Result();
        try {

            Distributor distributor;
            if (distributorId != null) {
                distributor = queryChannelService.findOne(QDistributor.distributor.id.eq(distributorId), Distributor.class);
            } else {
                WebUser user = Securitys.user(request);
                distributor = user.getDistributor();
                distributorId = distributor.getId();
            }
            Requires.notNull(distributor, "分销商不存在");

            String hql = "select g.thirdChannel from DistributionGoodsAssign g where g.distributor.id = :did";
            if (type == 1) {
                hql += " and g.status = 1";
            }
            List<Long> thirdIds = queryChannelService.findAll(hql, ImmutableMap.of("did", distributorId), Long.class);
            List<GoodsChannel> thirds = queryChannelService.findAll(QGoodsChannel.goodsChannel.id.in(thirdIds), GoodsChannel.class);
            Set<GoodsChannel> seconds = thirds.stream().map(GoodsChannel::getParent).collect(Collectors.toSet());
            Set<GoodsChannel> firsts = seconds.stream().map(GoodsChannel::getParent).collect(Collectors.toSet());

            List<Map<String, Object>> list = new ArrayList<>();

            for (GoodsChannel first : firsts) {
                Map<String, Object> firstMap = new HashMap<>();
                list.add(firstMap);

                firstMap.put("name", first.getName());
                List<Map<String, Object>> firstChild = new ArrayList<>();
                firstMap.put("children", firstChild);

                Set<GoodsChannel> secondList = new LinkedHashSet<>();
                for (GoodsChannel second : seconds) {
                    if (second.getParent() == first) {
                        secondList.add(second);
                    }
                }

                for (GoodsChannel second : secondList) {
                    Map<String, Object> secondMap = new LinkedHashMap<>();
                    firstChild.add(secondMap);

                    secondMap.put("name", second.getName());
                    List<Map<String, Object>> secondChild = new ArrayList<>();
                    secondMap.put("children", secondChild);

                    Set<GoodsChannel> thirdList = new LinkedHashSet<>();
                    for (GoodsChannel third : thirds) {
                        if (third.getParent() == second) {
                            thirdList.add(third);
                        }
                    }

                    for (GoodsChannel channel : thirdList) {
                        Map<String, Object> map = new HashMap<>();
                        map.put("name", channel.getName());
                        map.put("id", channel.getId());
                        map.put("icon", StringUtils.isBlank(channel.getIcon()) ? null : storeDomain + "/uploads/" + channel.getIcon());
                        secondChild.add(map);
                    }
                }
            }

            return result.ok().inject(ImmutableMap.of("list", list));

        } catch (IllegalArgumentException e) {
            return result.fail().setMsg(e.getMessage());
        } catch (Exception e) {
            log.error("[获取分销商品分类异常]", e);
            return result.fail().setMsg("获取数据异常");
        }
    }


    /**
     * 选择展示分销商品
     */
    @PostMapping("/selectGoods")
    public Result selectGoods(HttpServletRequest request, @RequestBody DistributionSelectGoodsDTO dto) {

        Result result = new Result();
        try {

            Requires.isTrue(dto.getType() > 0 && dto.getType() < 4, "类型不正确");

            WebUser user = Securitys.user(request);
            Distributor distributor = user.getDistributor();
            Requires.notNull(distributor, "当前用户不是分销商");

            if (dto.getType() == 1) {
                distributorApplication.selectAllGoods(distributor);
            } else if (dto.getType() == 2) {
                distributorApplication.selectChannelGoods(distributor, dto.getIds());
            } else {
                distributorApplication.selectGoods(distributor, dto.getIds());
            }

            return result.ok();

        } catch (IllegalArgumentException e) {
            return result.fail().setMsg(e.getMessage());
        } catch (Exception e) {
            log.error("[选择分销商品异常]", e);
            return result.fail().setMsg("提交异常");
        }
    }


    /**
     * 分销商品池列表
     *
     * @param priceOrder      按价格排序 1、升序 2、降序
     * @param scaleOrder      按佣金排序 1、升序 2、降序
     * @param saleNumberOrder 按销量排序 1、升序 2、降序
     * @param storeOrder      按库存排序 1、升序 2、降序
     * @param channels        商品分类
     * @param goodsName       商品名称
     * @param maxPrice        最高价格
     * @param minPrice        最低价格
     * @param maxScale        最高分佣
     * @param minScale        最低分佣
     * @param maxStore        最高库存
     * @param minStore        最低库存
     * @param merchantName    商家名称
     */
    @GetMapping("/goodsPool")
    public Result goodsPool(HttpServletRequest request, @RequestParam(defaultValue = "1") int pageNo,
                            @RequestParam(defaultValue = "10") int pageSize,
                            Integer priceOrder, Integer scaleOrder, Integer saleNumberOrder, Integer storeOrder, String
                                    goodsName, String merchantName, Double minPrice,
                            Double maxPrice, Integer minScale, Integer maxScale, Integer maxStore, Integer minStore, String
                                    channels) {
        Result result = new Result();
        try {

            WebUser user = Securitys.user(request);
            Distributor distributor = user.getDistributor();

            QueryPageRequest pageRequest = new QueryPageRequest().setPageNo(pageNo).setPageSize(pageSize);
            Map<String, Object> map = new HashMap<>();

//            String hql = "select g from DistributionGoods g where g.status = 1 ";
            String hql = "select g.distributionGoods from DistributionGoodsAssign g where g.distributor.id = :did and g.distributionGoods.status = 1 ";
            map.put("did", distributor.getId());

            if (StringUtils.isNotBlank(goodsName)) {
                hql += " and g.distributionGoods.goods.name like :goodsName";
                map.put("goodsName", "%" + goodsName + "%");
            }

            if (StringUtils.isNotBlank(merchantName)) {
                hql += " and g.distributionGoods.goods.merchant.nickname like :merchantName";
                map.put("merchantName", "%" + merchantName + "%");
            }

            if (minPrice != null) {
                hql += " and g.distributionGoods.goods.defaultPrice >= :minPrice";
                map.put("minPrice", minPrice);
            }

            if (maxPrice != null && minPrice != null && maxPrice >= minPrice || maxPrice != null && minPrice == null) {
                hql += " and g.distributionGoods.goods.defaultPrice <= :maxPrice";
                map.put("maxPrice", maxPrice);
            }

            if (minStore != null) {
                hql += " and g.distributionGoods.goods.store >= :minStore";
                map.put("minStore", minStore);
            }

            if (maxStore != null && minStore != null && maxStore >= minStore || maxStore != null && minStore == null) {
                hql += " and g.distributionGoods.goods.store <= :maxStore";
                map.put("maxStore", maxStore);
            }

            if (minScale != null) {
                double scale = ArithUtils.roundHalfUp(1 - (double) minScale / 100, 2);
                hql += " and g.distributionGoods.guaranteeScale <= :minScale";
                map.put("minScale", scale);
            }

            if (maxScale != null && (minScale == null || maxScale >= minScale)) {
                double scale = ArithUtils.roundHalfUp(1 - (double) maxScale / 100, 2);
                hql += " and g.distributionGoods.guaranteeScale >= :maxScale";
                map.put("maxScale", scale);
            }

            if (StringUtils.isNotBlank(channels)) {
                List<Long> channelIds = Splitter.on(";").omitEmptyStrings().trimResults().splitToList(channels).stream().map(Long::valueOf).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(channelIds)) {
                    hql += " and g.distributionGoods.goods.goodsChannel.id in (:channelIds)";
                    map.put("channelIds", channelIds);
                }
            }

            if (priceOrder != null) {
                if (priceOrder == 1) {
                    hql += " order by g.distributionGoods.createTime asc";
                } else {
                    hql += " order by g.distributionGoods.createTime desc";
                }
            } else if (scaleOrder != null) {
                if (scaleOrder == 1) {
                    hql += " order by g.distributionGoods.guaranteeScale desc";
                } else {
                    hql += " order by g.distributionGoods.guaranteeScale asc";
                }
            } else if (saleNumberOrder != null) {
                if (saleNumberOrder == 1) {
                    hql += " order by g.distributionGoods.goods.salesVolume asc";
                } else {
                    hql += " order by g.distributionGoods.goods.salesVolume desc";
                }
            } else if (storeOrder != null) {
                if (storeOrder == 1) {
                    hql += " order by g.distributionGoods.goods.store asc";
                } else {
                    hql += " order by g.distributionGoods.goods.store desc";
                }
            } else {
                hql += " order by g.distributionGoods.rank asc";
            }

            QueryPage<DistributionGoods> page = queryChannelService.findPage(hql, pageRequest.setParams(map), DistributionGoods.class);

            List<DistributionGoodsDTO> list = new ArrayList<>();
            for (DistributionGoods distributionGoods : page.getResult()) {
                Goods goods = distributionGoods.getGoods();
                DistributionGoodsDTO dto = new DistributionGoodsDTO();
                dto.setGoodsId(goods.getId());
                dto.setDefaultPrice(goods.getDefaultPrice());
                dto.setDefaultImage(StringUtils.isBlank(goods.getDefaultImage()) ? null : storeDomain + "/uploads/" + goods.getDefaultImage());
                dto.setDistributorId(distributor.getId());
                dto.setGoodsName(goods.getName());
                dto.setScale(ArithUtils.roundHalfUp((1 - distributionGoods.getGuaranteeScale()) * 100, 2) + "%");
                dto.setStore(goods.getStore());
                dto.setMerchantName(Strings.nullToEmpty(distributor.getShopName()));
                list.add(dto);
            }

            return result.ok().inject(new QueryPage<>(page.getTotalCount(), list, pageNo, pageSize));

        } catch (IllegalArgumentException e) {
            return result.fail().setMsg(e.getMessage());
        } catch (Exception e) {
            log.error("[获取分销池商品异常]", e);
            return result.fail().setMsg("获取数据异常");
        }
    }

    /**
     * 海报列表
     *
     * @param type 1、拉新海报 2、商品海报 3、微店海报
     */
    @GetMapping("/posterList")
    public Result posterList(@RequestParam(defaultValue = "1") int pageNo,
                             @RequestParam(defaultValue = "10") int pageSize, @RequestParam(defaultValue = "1") int type) {

        Result result = new Result();
        try {
            QueryPageRequest pageRequest = new QueryPageRequest().setPageNo(pageNo).setPageSize(pageSize);
            String hql = "select p from DistributionPoster p where p.type = :type and p.status = 1";
            QueryPage<DistributionPoster> page = queryChannelService.findPage(hql, pageRequest.setParams(ImmutableMap.of("type", type)), DistributionPoster.class);

            for (DistributionPoster poster : page.getResult()) {
                poster.setImage(storeDomain + "/uploads/" + poster.getImage());
            }

            return result.ok().inject(page);

        } catch (IllegalArgumentException e) {
            return result.fail().setMsg(e.getMessage());
        } catch (Exception e) {
            log.error("[获取海报列表异常]", e);
            return result.fail().setMsg("获取数据异常");
        }
    }


    /**
     * 根据海报模板生成海报图片
     */
    @PostMapping("/generatePosterImage")
    public Result generatePosterImage(@RequestBody DistributionPoster params, HttpServletRequest request) {

        Result result = new Result();
        try {

            DistributionPoster distributionPoster = queryChannelService.findOne(DistributionPoster.class, params.getId());
            Requires.isTrue(distributionPoster != null && distributionPoster.getStatus() == 1, "海报不存在");

            WebUser user = Securitys.user(request);
            if (distributionPoster.getType() == 3 && params.getDistributorId() != null) {
                user = queryChannelService.findOne(Distributor.class, params.getDistributorId()).getUser();
            }
            String filename = distributionPosterApplication.generatePosterImage(params, user);
            return result.ok().inject(ImmutableMap.of("url", storeDomain + "/uploads/" + filename));

        } catch (IllegalArgumentException e) {
            return result.fail().setMsg(e.getMessage());
        } catch (Exception e) {
            log.error("[生成分享图片异常]", e);
            return result.fail().setMsg("生成异常");
        }
    }


    /**
     * 申请提现
     */
    @PostMapping(value = "/withdraw")
    public Result submit(HttpServletRequest request, @RequestBody DistributorWithdrawRecord params) {
        Result result = new Result();
        try {
            WebUser user = Securitys.user(request);
            Requires.notNull(user.getDistributor(), "当前用户不是分销商");
            Requires.isTrue(user.getDistributor().getBalance() >= params.getWithDrawMoney(), "余额不足");

            DistributionSetting setting = distributionSettingApplication.findLastSetting();

            if (setting.getMinPrice() != null) {
                Requires.isTrue(params.getWithDrawMoney() >= setting.getMinPrice(), "提现最小金额" + setting.getMinPrice());
            }
            if (setting.getMaxPrice() != null) {
                Requires.isTrue(params.getWithDrawMoney() <= setting.getMaxPrice(), "提现最大金额" + setting.getMaxPrice());
            }
            if (setting.getWithdrawNumPerDay() != null) {
                int count = queryChannelService.selectCount("select count(*) from distributor_withdraw_record where distributor_id = :did and date(createTime) = date(now())", ImmutableMap.of("did", user.getDistributor().getId()));
                Requires.isTrue(count < setting.getWithdrawNumPerDay(), "提现已达当天最大次数");
            }
            if (setting.getWithdrawNumPerMonth() != null) {
                int count = queryChannelService.selectCount("select count(*) from distributor_withdraw_record where distributor_id = :did and datediff(now(), createTime) <= 30", ImmutableMap.of("did", user.getDistributor().getId()));
                Requires.isTrue(count < setting.getWithdrawNumPerMonth(), "提现已达当月最大次数");
            }

            DistributorWithdrawRecord record = new DistributorWithdrawRecord();
            record.setPayType(setting.getCommissionPayType());
            record.setWithDrawMoney(params.getWithDrawMoney());
            record.setRecordNo(DateFormatUtils.format(new Date(), "yyyyMMddHHmmss") + RandomStringUtils.randomNumeric(6));
            record.setDistributor(user.getDistributor());

            //银行卡
            if (setting.getCommissionPayType() == 2) {
                Requires.notNull(params.getBankCardId(), "银行卡不能为空");
                BankCard card = queryChannelService.findOne(BankCard.class, params.getBankCardId());

                record.setBankName(card.getBankName());
                record.setBankCardNo(card.getBankCardNo());
                record.setBankProvince(card.getBankProvince());
                record.setBankCity(card.getBankCity());
                record.setBankSubBranch(card.getBankSubBranch());
                record.setBankAccoutName(card.getAccountName());
            }

            record.setStatus(1);
            distributorWithdrawRecordApplication.create(record);
            return result.ok();

        } catch (IllegalArgumentException e) {
            return result.fail().setMsg(e.getMessage());
        } catch (Exception e) {
            log.error("[申请提现异常]", e);
            return result.fail().setMsg("申请异常");
        }
    }

    /**
     * 提现列表
     */
    @GetMapping("/withdrawList")
    public Result list(HttpServletRequest request, @RequestParam(defaultValue = "1") int pageNo,
                       @RequestParam(defaultValue = "20") int pageSize, @RequestParam(defaultValue = "0") int status) {
        Result result = new Result();
        try {

            WebUser member = Securitys.user(request);
            Requires.notNull(member.getDistributor(), "当前用户不是分销商");

            QueryPageRequest pageRequest = new QueryPageRequest().setPageNo(pageNo).setPageSize(pageSize);
            Map<String, Object> params = new HashMap<>();
            params.put("did", member.getDistributor().getId());

            String hql = builderHql(params, status);
            QueryPage<DistributorWithdrawRecord> page = queryChannelService.findPage(hql, pageRequest.setParams(params), DistributorWithdrawRecord.class);

            return result.ok().inject(ImmutableMap.of("page", page));

        } catch (Exception e) {
            log.error("[订单列表异常]", e);
            return result.fail().setMsg("网络请求异常");
        }
    }

    private String builderHql(Map<String, Object> params, int status) {
        String hql = "select r from DistributorWithdrawRecord r where r.distributor.id = :did";
        if (status > 0) {
            hql += " and r.status = :status ";
            params.put("status", status);
        }
        return hql + " order by r.createTime desc ";
    }


    /**
     * 订单列表
     */
    @GetMapping("/orderList")
    public Result orderList(HttpServletRequest request,
                            @RequestParam(defaultValue = "1") int pageNo,
                            @RequestParam(defaultValue = "20") int pageSize,
                            @RequestParam(defaultValue = "0") int status, Integer source) {
        Result result = new Result();
        try {
            Distributor distributor = Securitys.user(request).getDistributor();
            Requires.notNull(distributor, "当前用户不是分销商");

            QueryPageRequest pageRequest = new QueryPageRequest().setPageSize(pageSize).setPageNo(pageNo);
            Map<String, Object> map = new HashMap<>();
            map.put("did", distributor.getId());

            String hql = "select o from LiveOrder o where o.distributor.id = :did";
            if (status > 0) {
                hql += " and o.distrtionPay = :distrtionPay";
                map.put("distrtionPay", status);
            } else {
                hql += " and o.distrtionPay in (1, 2)";
            }

            if (source != null) {
                hql += " and o.source = :source";
                map.put("source", source);
            }
            hql += " order by o.createTime desc";

            QueryPage<DistributionOrder> page = queryChannelService.findPage(hql, pageRequest.setParams(map), DistributionOrder.class);

            List<Map<String, Object>> list = new ArrayList<>();
            for (DistributionOrder order : page.getResult()) {
                Map<String, Object> item = new HashMap<>();
                item.put("orderNo", order.getOrder().getOrderNo());
                item.put("source", order.getSource());
                item.put("orderStatus", order.getOrder().getStatus());
                item.put("distrtionPay", order.getDistrtionPay());
                item.put("goodsName", order.getOrder().getDetails().get(0).getSku().getGoods().getName());
                item.put("goodsImage", storeDomain + "/uploads/" + order.getOrder().getDetails().get(0).getSku().getGoods().getDefaultImage());
                item.put("price", order.getOrder().getPrice());
                item.put("money", order.getMoney());
                item.put("specs", order.getOrder().getDetails().get(0).getSpecs());
                item.put("nums", order.getOrder().getDetails().get(0).getQuantity());
                list.add(item);
            }
            return result.ok().inject(new QueryPage<>(page.getTotalCount(), list, pageNo, pageSize));

        } catch (IllegalArgumentException e) {
            return result.fail().setMsg(e.getMessage());
        } catch (Exception e) {
            log.error("[获取订单列表异常]", e);
            return result.fail().setMsg("获取数据异常");
        }
    }

    /**
     * 获取合伙须知人申请协议
     */
    @GetMapping("/protocol")
    public Result protocol() {
        Result result = new Result();
        try {
            DistributionSetting distributionSetting = distributionSettingApplication.findLastSetting();
            return result.ok().inject(ImmutableMap.of("content", distributionSetting == null ? "" : Strings.nullToEmpty(distributionSetting.getApplyNote())));
        } catch (Exception e) {
            log.error("[获取合伙须知人申请协议异常]", e);
            return result.fail().setMsg("获取数据异常");
        }
    }

}
